#include "NormalFileDecoder.h"

#include "../inc/Utils.h"


NormalFileDecoder::NormalFileDecoder(void)
{
	pFormatCtx = NULL;
	pSwsCtxBGR32 = NULL;
	codec = NULL;
	c = NULL;
	frame = NULL;
	frameBGR = NULL;
}


NormalFileDecoder::~NormalFileDecoder(void)
{
	playFlag = STOP;
	if(decodeThread != NULL)
	{
		//TerminateThread(startThread, 0);
		decodeThreadRunning = false;
		pthread_join(decodeThread, NULL);
		decodeThread = NULL;
	}
	if(pFormatCtx != NULL)
	{
		avformat_close_input(&pFormatCtx);
	}
	if(frame != NULL)
		av_frame_free(&frame);

	if(frameBGR != NULL)
		avpicture_free((AVPicture*) frameBGR);

	sws_freeContext(pSwsCtxBGR32);

	_print_log("NormalFileDecoder released\n");
}


void NormalFileDecoder::startRecvThread()
{
}

void NormalFileDecoder::startDecodeThread()
{
	av_register_all();
	avformat_network_init();
	av_init_packet(&avpkt);

	// Open video file
	int retval = avformat_open_input(&pFormatCtx, filename, NULL, NULL);
	while (retval != 0)
	{
		usleep(1000);
		_print_log("filename:%s\n", filename);
		_print_log("Couldn't open file\n");
		retval = avformat_open_input(&pFormatCtx, filename, NULL, NULL);
	}

	// Retrieve stream information
	if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
	{
		_print_log("Couldn't find stream information\n");
		retval = -1;
	}
	else
	{// success
	}

	// Find the first video stream
	int videoStream = -1;
	for (unsigned int i = 0; i < pFormatCtx->nb_streams; i++)
	{
		if (pFormatCtx->streams[i]->codec->codec_type
			== AVMEDIA_TYPE_VIDEO)
		{
			videoStream = i;
			break;
		}
	}
	if (videoStream == -1)
	{
		_print_log("Didn't find a video stream\n");
		retval = -1; // Didn't find a video stream
	}
	c = pFormatCtx->streams[videoStream]->codec;

	codec = avcodec_find_decoder(
		pFormatCtx->streams[videoStream]->codec->codec_id);
	if (codec == NULL)
	{
		_print_log("Unsupported codec!\n");
		return;// Codec not found
	}
	// Open codec
	if (avcodec_open2(pFormatCtx->streams[videoStream]->codec,
		codec, NULL) < 0)
	{
		_print_log("Could not open codec");
		return; // Could not open codec
	}

	frame = av_frame_alloc();
	if(frame == NULL)
	{
		_print_log("could not allocate video frame\n");
	}
	frameBGR = av_frame_alloc();
	if(frameBGR == NULL)
	{
		_print_log("could not allocate video frame\n");
	}

	while (av_read_frame(pFormatCtx, &avpkt) >= 0)
	{
		if(decodeThreadRunning != true)
			return;
		if(playFlag == PLAY)
		{
		}
		else if(playFlag == PAUSE)
		{
			usleep(1000);
			continue;
		}
		else if(playFlag == STOP)
		{
			break;
		}
		else
		{
			_print_log("illegal playflag\n");
			break;
		}


		progress+=avpkt.size;
		_print_log("avpkt.size:%d\n", avpkt.size);
		int len = 0, got_frame = 0;
		len = avcodec_decode_video2(c, frame, &got_frame, &avpkt);
		if(len < 0)
			_print_log("Error while decoding frame\n");
		if(got_frame)
		{
			//_print_log("%d, %d\n", width, height);
			//_print_log("success\n");
			//FILE* fd = fopen("d://1.pgm", "w");
			//fprintf(fd, "P5\n%d %d\n%d\n", width,height,255);
			//for(int i =0;i<height;i++)
			//	fwrite(frame->data[0] + i* frame->linesize[0] , 1, width, fd);
			//fclose(fd);
			if(frameBGR->data[0] == NULL)
			{
				width = frame->width;
				height = frame->height;
				pRGBData = (char*)malloc(width * height * 4);
				pSwsCtxBGR32 = sws_getContext(frame->width, frame->height,AV_PIX_FMT_YUV420P, width, height, AV_PIX_FMT_RGB32,SWS_BILINEAR,NULL,NULL,NULL);

				avpicture_alloc((AVPicture*)frameBGR, AV_PIX_FMT_RGB32, width, height);
			}
			frameBGR->width = width;
			frameBGR->height = height;
			int ret = sws_scale(pSwsCtxBGR32, frame->data,frame->linesize,0, frame->height,frameBGR->data,frameBGR->linesize);
			if(frameBGR->height != ret)
			{
				_print_log("sws_scale failed\n");
				continue;
			}

			if(filename[0] != 'r')
			{
				int interval = 1000 / (c->time_base.den / 2);
				if(interval < 40)
					usleep(40000);
				else
					usleep(interval * 1000);
			}
			frameInfo.width = width;
			frameInfo.height = height;
			(*DecodeCBFun)((char*)frameBGR->data[0], width * height * 4, &frameInfo, pUser);

		}
		av_free_packet(&avpkt);
	}

	//_endthread();
}
